#include "pch.hpp"
#include "Application.hpp"
#include "WinException.hpp"

using namespace WinUi;

Application* Application::m_theApp = 0;




Application::Application(const char* cmdLine)
	: m_fastPumping(false)
	, m_active(false)
	, idle(m_idle)
	, activated(m_activated)
	, deactivated(m_deactivated)
{
	std::vector<std::string> args = boost::program_options::split_winmain(GetCommandLineA());
	std::vector<const char*> argv;
	argv.reserve(args.size());

	foreach(const std::string& str, args)
		argv.push_back(str.c_str());

	// TODO: use command line arguments...

	m_theApp = this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Application::Application(int argc, const char* const* argv)
	: m_fastPumping(false)
	, m_active(false)
	, idle(m_idle)
	, activated(m_activated)
	, deactivated(m_deactivated)
{
	m_theApp = this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Application::~Application()
{
	m_theApp = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Application::setFastPumping(bool b)
{
	m_fastPumping = b;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool Application::fastPumping() const
{
	return m_fastPumping;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool Application::active() const
{
	return m_active;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




int Application::exec()
{
	try
	{
		MSG msg;
		ZeroMemory(&msg, sizeof(msg));
		while(msg.message != WM_QUIT)
		{
			if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else
			{
				// When idle() returns true (no slot quests fast pumping)
				// then we wait a bit, before peeking again
				if(!m_fastPumping)
					boost::this_thread::sleep(boost::posix_time::millisec(1));

				m_idle();
			}
		}

		// On Win64, WPARAM happens to be a LONG_PTR, thus being bigger
		// than int, however since even WinMain() returns an integer, it will
		// be safe to do so here as well.
		return static_cast<int>(msg.wParam);
	}
	catch(const exception& except)
	{
		std::string text = format("An exception causes this application to shut down. I'm sorry for the inconvenience this may cause. Please press Ok to close the Application.\n\n%1%") % boost::diagnostic_information(except);
		messageBox("An exception has been caught", text);
		return -1;
	}
	catch(const std::exception& except)
	{
		std::string what = except.what();
		std::string text = format("An exception causes this application to shut down. I'm sorry for the inconvenience this may cause. Please press Ok to close the Application.\n\n%1%") % what;
		messageBox("An error ocurred", text);
		return -1;
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Application::quit(int exitCode)
{
	PostQuitMessage(exitCode);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Application::exit()
{
	quit(0);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Application& Application::instance()
{
	if(!m_theApp)
		BOOSTEXT_THROW(boostext::critical_exception("There is no Application instance, it must be created first"));

	return *m_theApp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Application::initGui()
{
	INITCOMMONCONTROLSEX tmp;
	ZeroMemory(&tmp, sizeof(tmp));
	tmp.dwSize = sizeof(tmp);
	tmp.dwICC = ICC_WIN95_CLASSES |
		ICC_STANDARD_CLASSES;

	if(!InitCommonControlsEx(&tmp))
		BOOSTEXT_THROW(WinApiException("InitCommonControlsEx(&tmp) failed"));
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Application::activate()
{
	if(!m_active)
	{
		m_active = true;
		m_activated();
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Application::deactivate()
{
	if(m_active)
	{
		m_active = false;
		m_deactivated();
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Application::messageBox(const std::string& title, const std::string& message)
{
	MessageBoxA(NULL, message.c_str(), title.c_str(), MB_OK);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
